#pragma once

#include "imgui/imgui.h"
#include <iostream>
#include <vector>


namespace ImGui
{
	struct Editor {


		struct Funcs
		{
			static int MyResizeCallback(ImGuiInputTextCallbackData* data)
			{
				if (data->EventFlag == ImGuiInputTextFlags_CallbackResize)
				{
					ImVector<char>* my_str = (ImVector<char> *)data->UserData;
					IM_ASSERT(my_str->begin() == data->Buf);

					my_str->resize(data->BufSize); // NB: On resizing calls, generally data->BufSize == data->BufTextLen + 1
					data->Buf = my_str->begin();
				}
				return 0;
			}

			// Note: Because ImGui:: is a namespace you would typically add your own function into the namespace.
			// For example, you code may declare a function 'ImGui::InputText(const char* label, MyString* my_str)'
			static bool MyInputTextMultiline(const char* label, ImVector<char>* my_str, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = 0)
			{
				IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0);
				return ImGui::InputTextMultiline(label, my_str->begin(), (size_t)my_str->size(), size,
					flags | ImGuiInputTextFlags_CallbackResize, Funcs::MyResizeCallback, (void*)my_str);
			}
		};


		bool InputMultiString(const std::string& label, std::string& value, int row);
		bool InputMultiString(const std::string label, ImVector<char>& my_str, int row);
		bool InputString(const std::string label, std::string& value);

		bool Checkbox(const std::string& label, int& open, int index);
		bool TreeNode(const std::string& label, int& open, int index, ImGuiTreeNodeFlags flag = 0);
		void TreePop()
		{
			ImGui::TreePop();
		}
		template<typename T>
		bool Edit(const std::string& label, T& t);

		template <typename T>
		bool EditInst(const std::string &label, T &t)
		{
			ImGui::PushID(&t);
			bool res = Edit<T>(label, t);
			ImGui::PopID();
			return res;
		}
		

		template<typename EnumType, typename DescType>
		bool Combo(const std::string& label, const std::vector<DescType>& descTypes, EnumType& inst, int startIndex = 1, int endIndex = 0)
		{
			const auto& desc = descTypes[inst];

			bool beginCombo = ImGui::BeginCombo(label.c_str(), desc.m_Name.c_str());

			bool selectable = false;

			if(beginCombo)
			{
				int numDescs = descTypes.size();

				for (int i = startIndex; i < numDescs + endIndex; i++)
				{
					const auto& it = descTypes[i];
					bool itSelected = ImGui::Selectable(it.m_Name.c_str());
					selectable |= itSelected;

					if (itSelected)
					{
						memcpy(&inst, &i, sizeof(i));
					}
				}
				ImGui::EndCombo();
			}
			return selectable;
		}

		template<typename EnumType, typename DescType>
		bool ComboInst(const std::string& label, const std::vector<DescType>& descTypes, EnumType& inst, int startIndex = 1, int endIndex = 0)
		{
			ImGui::PushID(&inst);
			bool res = Combo<EnumType, DescType>(label, descTypes, inst, startIndex, endIndex);
			ImGui::PopID();
			return res;
		}

		static void SetBit(int& value, int off, bool bit)
		{
			if (value)
				value |= (1 << off);  // Set the bit if the node is opened
			else
				value &= ~(1 << off); // Clear the bit if the node is closed
		};

		static bool GetBit(int value, int off)
		{
			bool bitMap = (value & (1 << off));
			return bitMap;
		};
		template<typename T>
		bool CheckBoxInst(const std::string& label, T& t)
		{
			ImGui::PushID(&t);
			bool v = (bool)t;
			bool res = ImGui::Checkbox(label.c_str(), &v);
			t = v;
			ImGui::PopID();
			return res;
		}
	};
}